﻿using UnityEngine;
using System.Collections.Generic;

[RequireComponent(typeof(MoveComponent))]
public class Character : Interactive
{
	public delegate void Callback();
	public static Callback actionEnded;
	public static Callback characterModified;

	[Header("Character")]
	public List<Tile> walkArea = new List<Tile>();
	public List<Tile> attackArea = new List<Tile>();

	public int totalActions = 2;
	public int currentActions = 2;

	private GameObject actionObject;
	private string actionMethod;
	private MoveComponent move;
	private BodyType attackBodyType;
	private Character attackTarget;

	#region MONO Methods
	protected override void Awake()
	{
		base.Awake();
		
		move = GetComponent<MoveComponent>();
		move.finishedMove += FollowPathFinished;
		//actionEnded += RecalculateAreas;
	}
	
	protected override void Start()
	{
		base.Start();

		if (InitiativeManager.Instance.characters.Count == 0)
		{
			InitiativeManager.Instance.RegisterCharacter(this);
			ActionEnded();
		}
	}
	#endregion MONO Methods

	public override bool ActivateInteractive()
	{
		bool firstActivation = base.ActivateInteractive();
		if (firstActivation)
		{
			InitiativeManager.Instance.RegisterCharacter(this);
		}

		return firstActivation;
	}

	// Called in Awake by Interactive
	public override void RecalculateAreas()
	{
		if (currentTile != null)
		{
			currentTile.SetObjectOnTop(null);
		}

		base.RecalculateAreas();

		if (!GetInfo().hidden)
		{
			walkArea = Area.WalkArea(currentTile, (int)GetInfo<CharacterInfo>().speed.minValue);
			attackArea = Area.AttackArea(currentTile, this);
			selectArea = Area.SelectArea(currentTile);

			currentTile.SetObjectOnTop(this);
		}
	}

	public bool BeAttacked(CharacterInfo _attacker, BodyType _body)
	{
		GetInfo<CharacterInfo>().BeAttacked(_attacker, _body);
		CharacterModified();

		return true;
	}

	public void StartTurn()
	{
		currentActions = totalActions;
		CharacterModified();

		RefManager.Instance.playerIndicator.SetTarget(trans, GetInfo().mainColor);
		StartAction();
	}

	public void FinishAction()
	{
		currentActions--;
		
		ActionEnded();
		CharacterModified();

		if (currentActions <= 0)
		{
			InitiativeManager.Instance.NextCharacter();
		}
		else
		{
			StartAction();
		}
	}

	protected virtual void StartAction()
	{
		// Do nothing
	}

	public void PerformAction(Interactive _inter, string _method, List<Tile> _path)
	{
		actionObject = _inter.gameObject;
		actionMethod = _method;

		FollowPath(_path);
	}

	public void PerformAttack(Character _target, BodyType _targetBody, List<Tile> _path)
	{
		attackTarget = _target;
		attackBodyType = _targetBody;

		FollowPath(_path);
	}

	public void GotoTile(Tile _tile)
	{
		FollowPath(Search.GetPath(currentTile, _tile, walkArea));
	}
	
	public void FollowPath(List<Tile> _path)
	{
		List<Vector3> path = new List<Vector3>();
		foreach (Tile tile in _path)
		{
			path.Add(tile.transform.position);
		}
		
		move.FollowPath(path);
		selectArea.Clear();
	}
	
	protected virtual void FollowPathFinished()
	{
		// Deactivate all objects
		FloorManager.Instance.DeactivateInteractives();
		AreaCreator.RemoveArea();
		AreaCreator.RemovePath();

		// Send method to object selected
		if (actionObject != null)
		{
			move.LookAt(actionObject.transform.position);
			actionObject.SendMessage(actionMethod);
			actionObject = null;
		}
		else if (attackTarget != null)
		{
			move.LookAt(attackTarget.transform.position);
			attackTarget.BeAttacked(GetInfo<CharacterInfo>(), attackBodyType);
			attackTarget = null;
		}

		FinishAction();
	}

	public void PickupObject(Useable _useable)
	{
		GetInfo<CharacterInfo>().AddContent(_useable.GetInfo());
		Destroy(_useable.gameObject);
	}
	
	#region STATIC
	public static void CharacterModified()
	{
		foreach (Character c in InitiativeManager.Instance.characters)
		{
			c.RecalculateAreas();
		}
		
		if (characterModified != null)
		{
			characterModified();
		}
	}
	
	public static void ActionEnded()
	{
		if (actionEnded != null)
		{
			actionEnded();
		}
	}
	#endregion STATIC
}
